using System;
using System.Threading.Tasks;
using System.Windows.Input;
/*
 * 源码已托管：https://gitee.com/dlgcy/WPFTemplate
 */
namespace WPFTemplateLib.WpfHelpers
{
    /// <summary>
    /// WPF 命令公共类;
    /// </summary>
    /// <example>
    /// <code>
    /// class Sample
    /// {
    ///     public ICommand DoSomethingCommand { get; set; }
    /// 
    ///     public Sample()
    ///     {
    ///         SetCommandMethod();
    ///     }
    /// 
    ///     /// <summary>
    ///     /// 命令方法赋值（在构造方法中调用）
    ///     /// </summary>
    ///     private void SetCommandMethod()
    ///     {
    ///         DoSomethingCommand ??= new RelayCommand(o => true, async o =>
    ///         {
    ///             // do something
    ///         });
    ///     }
    /// }
    /// </code>
    /// </example>
    public class RelayCommand : ICommand
    {
        private readonly Predicate<object> _canExecute;
        private readonly Action _executeWithoutPara;
        private readonly Action<object> _execute;
		private readonly Func<object, Task> _executeAsync;

        public RelayCommand(Predicate<object> canExecute, Action<object> execute)
        {
            _canExecute = canExecute;
            _execute = execute;
        }

        public RelayCommand(Predicate<object> canExecute, Func<object, Task> executeAsync)
        {
            _canExecute = canExecute;
            _executeAsync = executeAsync;
        }

		public RelayCommand(Action executeWithoutPara)
		{
			_executeWithoutPara = executeWithoutPara;
		}

		public RelayCommand(Action<object> execute)
        {
            _execute = execute;
        }

        public RelayCommand(Func<object, Task> executeAsync)
        {
            _executeAsync = executeAsync;
        }

        public event EventHandler CanExecuteChanged
        {
            add => CommandManager.RequerySuggested += value;
            remove => CommandManager.RequerySuggested -= value;
        }

        public bool CanExecute(object parameter)
        {
            return _canExecute?.Invoke(parameter) ?? true;
        }

        public void Execute(object parameter)
        {
			if(_executeWithoutPara != null)
			{
				_executeWithoutPara();
			}
			else if(_execute != null)
            {
                _execute(parameter);
            }
            else if (_executeAsync != null)
            {
                _executeAsync.Invoke(parameter);
            }
        }
    }

    /// <summary>
    /// WPF 命令公共类（泛型版）
    /// </summary>
    /// <typeparam name="T">命令参数类型</typeparam>
    public class RelayCommand<T> : ICommand
    {
        private readonly Predicate<T> _canExecute;
        private readonly Action<T> _execute;
        private readonly Func<T, Task> _executeAsync;

        public RelayCommand(Predicate<T> canExecute, Action<T> execute)
        {
            _canExecute = canExecute;
            _execute = execute;
        }

        public RelayCommand(Predicate<T> canExecute, Func<T, Task> executeAsync)
        {
            _canExecute = canExecute;
            _executeAsync = executeAsync;
        }

        public RelayCommand(Action<T> execute) : this(null, execute) { }

        public RelayCommand(Func<T, Task> executeAsync) : this(null, executeAsync) { }

        public event EventHandler CanExecuteChanged
        {
            add => CommandManager.RequerySuggested += value;
            remove => CommandManager.RequerySuggested -= value;
        }

        public bool CanExecute(object parameter)
        {
            return _canExecute?.Invoke((T)parameter) ?? true;
        }

        public void Execute(object parameter)
        {
            if (_execute != null)
            {
                _execute((T)parameter);
            }
            else if (_executeAsync != null)
            {
                _executeAsync.Invoke((T)parameter);
            }
        }
    }
}
